using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Threading;
using System.Net;
using System.Net.Sockets;

using System.Runtime.InteropServices;

namespace OpenMessenger.Cliente
{
    public partial class Form1 : Form
    {
        Socket client;
        EndPoint remoteEP;
        byte[] data;
        delegate void SetTextCallback(string text);
        delegate void CambiarEstadoConectarCallback(bool permiteConectar);
        int recv;
        Thread thread1;
        bool desconectar = true;

        // WinApi Beep() is in kernel32.dll
        [DllImport("kernel32")]
        private static extern int Beep(int dwFreq, int dwDuration);

        public Form1()
        {
            InitializeComponent();

            if (System.Configuration.ConfigurationSettings.AppSettings["Servidor"] != null)
                txtIpServer.Text = System.Configuration.ConfigurationSettings.AppSettings["Servidor"];
            if (System.Configuration.ConfigurationSettings.AppSettings["Puerto"] != null)
                txtPort.Text = System.Configuration.ConfigurationSettings.AppSettings["Puerto"];
        }

        private byte[] ObtenerBytes(string mensaje)
        {
            return Encoding.UTF8.GetBytes(mensaje);
        }

        private string ObtenerString(byte[] p_data, int tamanio)
        {
            return Encoding.UTF8.GetString(p_data, 0, tamanio);
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                desconectar = true;

                client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                remoteEP = new IPEndPoint(IPAddress.Parse(txtIpServer.Text.Trim()), int.Parse(txtPort.Text.Trim()));
                client.SendTo(ObtenerBytes("join "+txtNick.Text), remoteEP);
                data = new byte[1024];
                thread1 = new Thread(new ThreadStart(Recibir));
                thread1.Start();

                btnConnect.Enabled = false;
                btnDisconnect.Enabled = true;

                txtIpServer.Enabled = false;
                txtPort.Enabled = false;
                txtNick.Enabled = false;
                txtMensajeSalida.Enabled = true;

                txtMensajeSalida.Text = "";
            }
            catch
            {
                MensajesUI.MostrarMensajeAdvertencia(this,"Hubo un problema al tratar de conectarse al servidor.");
            }
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            Desconectar();
            btnConnect.Enabled = true;
            btnDisconnect.Enabled = false;

            txtIpServer.Enabled = true;
            txtPort.Enabled = true;
            txtNick.Enabled = true;
            txtMensajeSalida.Enabled = false;
        }

        private void Desconectar()
        {
            if (thread1 != null)
                thread1.Abort();

            if(client!=null)
                client.SendTo(ObtenerBytes("quit "+txtNick.Text), remoteEP);
        }

        private void btnEnviar_Click(object sender, EventArgs e)
        {
            Enviar();
        }

        public void Enviar()
        {
            client.SendTo(ObtenerBytes(txtNick.Text.Trim() + " :" + txtMensajeSalida.Text.Trim()), remoteEP);
            txtMensajeSalida.Text = "";
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Desconectar();
        }

        public void Recibir()
        {
            try
            {
                while (true)
                {
                    recv = client.ReceiveFrom(data, ref remoteEP);
                    CopiarHistorial(ObtenerString(data,recv) + "\r\n");
                    AlertaSonora();
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception exc)
            {
                if (desconectar)
                    CambiarEstadoBotones(true);

                MensajesUI.MostrarMensajeAdvertencia(null, "Ocurrio un problema con el servidor. Detalles: " + exc.Message);
            }
        }

        private void AlertaSonora()
        {
            if (!chkActivarSonido.Checked)
                return;

            Beep(220, 100);
            Beep(880, 100);
        }

        private void CambiarEstadoBotones(bool permiteConectar)
        {
            if (this.btnConnect.InvokeRequired || this.btnDisconnect.InvokeRequired)
            {
                CambiarEstadoConectarCallback d = new CambiarEstadoConectarCallback(CambiarEstadoBotones);
                this.Invoke(d, new object[] { permiteConectar });
            }
            else
            {
                btnConnect.Enabled = permiteConectar;
                btnDisconnect.Enabled = !permiteConectar;
            }
        }

        private void CopiarHistorial(string text)
        {
            if (this.txtHistorial.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(CopiarHistorial);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.txtHistorial.Text += text;
            }
        }

        private void txtMensajeSalida_TextChanged(object sender, EventArgs e)
        {
            btnEnviar.Enabled = (txtMensajeSalida.Text.Length > 0);
            this.AcceptButton = btnEnviar;
        }
    }
}